package com.kqzz.common.utils;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.IOUtils;

import javax.crypto.Cipher;
import java.io.ByteArrayOutputStream;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;


/**
 * @description: RSA加密解密类
 * @version <1> 2022-01-11
 */
public class RSAUtils {

    public static final String CHARSET = "UTF-8";
    /**
     * 加密算法RSA
     */
    public static final String RSA_ALGORITHM = "RSA";

    // 私钥密匙字符串
    public static String privateKey = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAJxRcBDOcUrHLjTui3SBC7XpCIoWxQVXpI8zsmk6C6_PmmY3qzkFn1zy7scjgKC8OxbLs0cZYCevCG-bjWfosxpQoCMfbMUeUDX66UuyPIptbL4Hr_RJdXY2Iw6cEUI0k5r9ZxAbYz-zCceRfBEnhzXTmWvQyIASIrOplxUfXtLZAgMBAAECgYAj_NvAAscyYAjTRtf0SoFXr_63S-awBC1uiohYkXR_VVxGjCpvRkwaKhOu5Q2H883mwZ7Uj5MDj9hxWW6ErZ4N5MWaKfEiS_0f_739G0TpH9DzNe426BbgUKr3ArMJvVNfKZ2XmkfPqc21jCQ7eab2kWS4n017cIknZv8KTegYwQJBAMjvmF46DD8fIoe811bVKxSbAQ_SGlxL3I-jp0CcBzolcVg2Y0xw_9TBZkmiiSx7el4y0-4H9KWAewU7jisZ7NcCQQDHJ7y2sL_6ntHObE3sELKb-VJvBP9IalcC4QENGljVjxIUAbB5tqDB0pJAFSBQP07_qTS6vetJzpu6PNQaxxfPAkEAqboo3D7wJUlpY3rR8pjxYOBljzWL6rZxwisclei1-hmymi6mxeUVVGNgwYY3lIlgnb0VYxT5Q-s4_vyFZEbr1QJACqXlQR9SJGQ5c3_26pg59HzwG195BrYo0M6W78xo04JCxS8R8HADSFmp2CNJBwFbh-_UEef1nIyfZuW5sXTToQJAGL9UOMQogWWBdfJ_dCHbrye6A2HzYRHjox-z_6YeFCC9dJrV_kjqRlsf_8usbW_8MydQO2m4BrjE1xoyhx5ktA";
    // 公钥密匙字符串
    public static String publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCcUXAQznFKxy407ot0gQu16QiKFsUFV6SPM7JpOguvz5pmN6s5BZ9c8u7HI4CgvDsWy7NHGWAnrwhvm41n6LMaUKAjH2zFHlA1-ulLsjyKbWy-B6_0SXV2NiMOnBFCNJOa_WcQG2M_swnHkXwRJ4c105lr0MiAEiKzqZcVH17S2QIDAQAB";


    /**
     * 公钥加密之后的结果
     *
     * @param paramStr
     * @return
     */
    public static String getPublicEncryptionResult(String paramStr) {
        // 得到公钥
        RSAPublicKey rsaPublicKey = null;
        try {
            rsaPublicKey = RSAUtils.getPublicKey(publicKey);
            // 公钥加密
            paramStr = RSAUtils.publicEncrypt(paramStr, rsaPublicKey);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            return null;
        }
        return paramStr;
    }

    /**
     * 私钥解密之后的结果
     *
     * @param paramStr
     * @return
     */
    public static String privateDecryptResult(String paramStr,String privateKey) {
        // 得到公钥
        RSAPrivateKey rsaPrivateKey = null;
        String result = "";
        try {
            rsaPrivateKey = RSAUtils.getPrivateKey(privateKey);
            // 私钥解密
            result = RSAUtils.privateDecrypt(paramStr, rsaPrivateKey);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            return null;
        }
        return result;
    }

    public static String privateDecryptResult(String paramStr) {
        // 得到公钥
        RSAPrivateKey rsaPrivateKey = null;
        String result = "";
        try {
            rsaPrivateKey = RSAUtils.getPrivateKey(privateKey);
            // 私钥解密
            result = RSAUtils.privateDecrypt(paramStr, rsaPrivateKey);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            return null;
        }
        return result;
    }

    public static String getPublicEncryptionResult(String paramStr,String publicKey) {
        // 得到公钥
        RSAPublicKey rsaPublicKey = null;
        try {
            rsaPublicKey = RSAUtils.getPublicKey(publicKey);
            // 公钥加密
            paramStr = RSAUtils.publicEncrypt(paramStr, rsaPublicKey);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            return null;
        }
        return paramStr;
    }

    /**
     * 得到公钥
     *
     * @param publicKey 密钥字符串（经过base64编码）
     * @throws Exception
     */
    public static RSAPublicKey getPublicKey(String publicKey) throws NoSuchAlgorithmException, InvalidKeySpecException {
        // 通过X509编码的Key指令获得公钥对象
        KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(Base64.decodeBase64(publicKey));
        RSAPublicKey key = (RSAPublicKey) keyFactory.generatePublic(x509KeySpec);
        return key;
    }

    /**
     * 得到私钥
     *
     * @param privateKey 密钥字符串（经过base64编码）
     * @throws Exception
     */
    public static RSAPrivateKey getPrivateKey(String privateKey)
            throws NoSuchAlgorithmException, InvalidKeySpecException {
        // 通过PKCS#8编码的Key指令获得私钥对象
        KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKey));
        RSAPrivateKey key = (RSAPrivateKey) keyFactory.generatePrivate(pkcs8KeySpec);
        return key;
    }

    /**
     * 私钥解密
     *
     * @param data
     * @param privateKey
     * @return
     */

    public static String privateDecrypt(String data, RSAPrivateKey privateKey) {
        try {
            Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, privateKey);
            return new String(rsaSplitCodec(cipher, Cipher.DECRYPT_MODE, Base64.decodeBase64(data),
                    privateKey.getModulus().bitLength()), CHARSET);
        } catch (Exception e) {
            throw new RuntimeException("解密字符串[" + data + "]时遇到异常", e);
        }
    }

    /**
     * 公钥加密
     *
     * @param data
     * @param publicKey
     * @return
     */
    public static String publicEncrypt(String data, RSAPublicKey publicKey) {
        try {
            Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, publicKey);
            return Base64.encodeBase64URLSafeString(rsaSplitCodec(cipher, Cipher.ENCRYPT_MODE, data.getBytes(CHARSET),
                    publicKey.getModulus().bitLength()));
        } catch (Exception e) {
            throw new RuntimeException("加密字符串[" + data + "]时遇到异常", e);
        }
    }

    private static byte[] rsaSplitCodec(Cipher cipher, int opmode, byte[] datas, int keySize) {
        int maxBlock = 0;
        if (opmode == Cipher.DECRYPT_MODE) {
            maxBlock = keySize / 8;
        } else {
            maxBlock = keySize / 8 - 11;
        }
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offSet = 0;
        byte[] buff;
        int i = 0;
        try {
            while (datas.length > offSet) {
                if (datas.length - offSet > maxBlock) {
                    buff = cipher.doFinal(datas, offSet, maxBlock);
                } else {
                    buff = cipher.doFinal(datas, offSet, datas.length - offSet);
                }
                out.write(buff, 0, buff.length);
                i++;
                offSet = i * maxBlock;
            }
        } catch (Exception e) {
            throw new RuntimeException("加解密阀值为[" + maxBlock + "]的数据时发生异常", e);
        }
        byte[] resultDatas = out.toByteArray();
        IOUtils.closeQuietly(out);
        return resultDatas;
    }

    /**
     * 创建公钥和私钥
     *
     * @param keySize
     * @return
     */
    public static Map<String, String> createKeys(int keySize) {
        // 为RSA算法创建一个KeyPairGenerator对象
        KeyPairGenerator kpg;
        try {
            kpg = KeyPairGenerator.getInstance(RSA_ALGORITHM);
        } catch (NoSuchAlgorithmException e) {
            throw new IllegalArgumentException("No such algorithm-->[" + RSA_ALGORITHM + "]");
        }

        // 初始化KeyPairGenerator对象,密钥长度
        kpg.initialize(keySize);
        // 生成密匙对
        KeyPair keyPair = kpg.generateKeyPair();
        // 得到公钥
        Key publicKey = keyPair.getPublic();
        String publicKeyStr = Base64.encodeBase64URLSafeString(publicKey.getEncoded());
        // 得到私钥
        Key privateKey = keyPair.getPrivate();
        String privateKeyStr = Base64.encodeBase64URLSafeString(privateKey.getEncoded());
        Map<String, String> keyPairMap = new HashMap<String, String>();
        keyPairMap.put("publicKey", publicKeyStr);
        keyPairMap.put("privateKey", privateKeyStr);

        return keyPairMap;
    }


}
